#include <stdio.h>
#include <pthread.h>
#include <iostream>

#include "util_thread.h"
#include "util_delay.h"
#include "crosslist_base.h"
#include "sys_inner.h"
#include "sys_heart.h"

using namespace std;

#define SYSHEART_INFO(...) fprintf(stdout, "\033[32m[SYSHEART_INFO] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stdout, __VA_ARGS__)
#define SYSHEART_ERR(...) fprintf(stderr, "\033[31m[SYSHEART_ERR] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stderr, __VA_ARGS__)

struct SysHeart;
struct SysHeartThread;

//每一种心跳类型开辟一个线程维护
struct SysHeartThread {
    SysHeartType type;
    //变频心跳,支持每个周期使用不同心跳间隔
    int* intervalArray = NULL; //心跳间隔us数组
    int32_t arrayIndex = 0; //interval数组的计数
    int32_t arrayLen = 0; //interval数组的长度
    //注册用户数组
    CrossList *usersList = NULL;
    //上级指针
    struct SysHeart* main = NULL;
};

//主结构体
struct SysHeart {
    volatile bool isExit; //全局结束标志
    volatile uint32_t syncTick; //线程时间同步用
    volatile int32_t threadCount; //当前在跑线程数
    volatile int32_t drawCount; //当前周期内需要绘制数
    SysHeartThread* threadArray; //init时分配 SYS_HERAT_TYPE_TOTAL 块内存
};

static SysHeart gSysHeart = {0};
extern SysInner *gSysInner;

// ----- 外部方法 -----

static void* SysHeartThreadFun(void* argv)
{
    SysHeartThread* th = (SysHeartThread*)argv;
    int32_t delayIndex = 0;

    th->main->threadCount += 1;

    while (!th->main->isExit)
    {
        UTIL_DELAY_NEXT_US(SYS_HEART_MIN_INTERVAL);

        if (th->usersList->Child() > 0)
        {
            if (--delayIndex < 1)
            {
                //遍历链表中的usr并回调
                th->usersList->Lock();

                CrossList *usrList = th->usersList->FirstChild();
                CrossList *usrListNext;
                while (usrList)
                {
                    SysHeartUser *usr = (SysHeartUser*)usrList->value;
                    usrListNext = usrList->Next();
                    //该usr已不是当前心跳类型
                    if (usr->type != th->type)
                    {
                        //无主的usr将直接释放内存
                        if (usr->type >= SYS_HERAT_TYPE_TOTAL)
                            delete usr;
                        //删除链表节点
                        delete usrList;
                    }
                    else
                    {
                        if (usr->callback)
                            th->main->drawCount += usr->callback(usr->priv, th->type, th->arrayIndex);
                    }
                    usrList = usrListNext;
                }

                th->usersList->UnLock();

                //获取下一次延时计数
                delayIndex = th->intervalArray[th->arrayIndex];
                //循环使用 intervalArray 数组
                if (++th->arrayIndex >= th->arrayLen)
                    th->arrayIndex = 0;
            }
        }
        //随时准备从序号0开始
        else
        {
            th->arrayIndex = 0;
            delayIndex = 0;
        }

        //最后一个到达这里的线程,负责调用刷屏
        //使用原子操作函数,syncTick先增加1,再返回
        if (__sync_add_and_fetch(&th->main->syncTick, 1) >= SYS_HERAT_TYPE_TOTAL)
        {
            //有绘制任务?
            if (th->main->drawCount > 0)
            {
                //在此刷屏
                SYSHEART_INFO("refresh screen by - type/%d interval/%d time/%s\r\n",
                    th->type, th->intervalArray[th->arrayIndex], UtilGetTimeStampSSMMMUUU());
                gSysInner->SysFlowDraw();
            }
            th->main->drawCount = 0;
            th->main->syncTick = 0;
        }
    }

    //清空链表,内存释放
    delete th->usersList;
    th->main->threadCount -= 1;
    return NULL;
}

SysHeartUser* SysHeartRegister(void *priv, SysHeartCallback callback, SysHeartType type)
{
    if (!gSysHeart.threadArray || gSysHeart.isExit)
        return NULL;
    SysHeartUser *usr = new SysHeartUser();
    usr->type = type;
    usr->priv = priv;
    usr->callback = callback;
    gSysHeart.threadArray[type].usersList->PushBackChild(new CrossList(usr));
    return usr;
}

int32_t SysHeartUnRegister(SysHeartUser* usr)
{
    if (!gSysHeart.threadArray || gSysHeart.isExit)
        return -1;
    //标记为无效的类型,后续被遍历到时会自动释放掉内存
    usr->type = SYS_HERAT_TYPE_TOTAL;
    return 0;
}

int32_t SysHeartSwitch(SysHeartUser* usr, SysHeartType type)
{
    if (!gSysHeart.threadArray || gSysHeart.isExit)
        return -1;
    usr->type = type;
    gSysHeart.threadArray[type].usersList->PushBackChild(new CrossList(usr));
    return 0;
}

int32_t SysHeartRefresh()
{
    if (!gSysHeart.threadArray || gSysHeart.isExit)
        return -1;
    gSysHeart.drawCount += 1;
    return 0;
}

// --------- 内部方法 ----------

int32_t SysInner::SysHeartInit()
{
    SysHeartThread* th;
    if (gSysHeart.threadArray)
        return 0;
    
    gSysHeart.isExit = false;
    gSysHeart.syncTick = 0;
    gSysHeart.threadCount = 0;
    gSysHeart.threadArray = new SysHeartThread[SYS_HERAT_TYPE_TOTAL]();

    for (int32_t i = 0; i < SYS_HERAT_TYPE_TOTAL; i++)
    {
        th = &gSysHeart.threadArray[i];
        th->type = (SysHeartType)i;
        th->main = &gSysHeart;
        th->usersList = new CrossList(NULL);

        //心跳类型定义
        switch (i)
        {
        case SYS_HERAT_TYPE_SLOW:
            th->arrayLen = 1;
            th->intervalArray = new int[th->arrayLen]{5};
            break;
        case SYS_HERAT_TYPE_NORMAL:
            th->arrayLen = 1;
            th->intervalArray = new int[th->arrayLen]{2};
            break;
        case SYS_HERAT_TYPE_FAST:
            th->arrayLen = 1;
            th->intervalArray = new int[th->arrayLen]{1};
            break;

        case SYS_HERAT_TYPE_MAP_ANIM:
            th->arrayLen = 3;
            th->intervalArray = new int[th->arrayLen]{5, 5, 5};
            break;

        case SYS_HERAT_TYPE_UNIT_STANDBY:
        case SYS_HERAT_TYPE_UNIT_SELECT:
            th->arrayLen = 3;
            th->intervalArray = new int[th->arrayLen]{5, 1, 5};
            break;
        case SYS_HERAT_TYPE_UNIT_RUNNING:
            th->arrayLen = 4;
            th->intervalArray = new int[th->arrayLen]{1, 1, 1, 1};
            break;

        default:
            continue;
        }

        UtilThreadNew(th, SysHeartThreadFun);
    }
    return 0;
}

int32_t SysInner::SysHeartDeInit()
{
    SysHeartThread* th;
    if (!gSysHeart.threadArray)
        return 0;

    gSysHeart.isExit = true;
    while (gSysHeart.threadCount > 0)
        UtilDelayUs(10000);
    
    for (int32_t i = 0; i < SYS_HERAT_TYPE_TOTAL; i++)
    {
        th = &gSysHeart.threadArray[i];
        if (th->intervalArray)
            delete[] th->intervalArray;
    }
    delete[] gSysHeart.threadArray;
    gSysHeart.threadArray = NULL;

    return 0;
}

